/**
 * Progetto PRAISED.
 * 13/dic/2010
 */
package it.uniroma3.dia.praised.pubmed.crawler;

import it.uniroma3.dia.praised.exception.CrawlerException;
import it.uniroma3.dia.praised.exception.FactoryException;
import it.uniroma3.dia.praised.factory.WebClientFactory;
import it.uniroma3.dia.praised.pubmed.model.Article;
import it.uniroma3.dia.praised.pubmed.parser.ParserPubMed;
import it.uniroma3.dia.praised.util.PubMedResultQueryParameters;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import com.gargoylesoftware.htmlunit.ElementNotFoundException;
import com.gargoylesoftware.htmlunit.html.HtmlAnchor;
import com.gargoylesoftware.htmlunit.html.HtmlPage;

/**
 * @author Accosta Augusto
 * @author Lopez Elisabetta
 *
 */
public class CrawlerPubMed {

	private HtmlPage page;
	
	private String url;
	private String query;
	private PubMedResultQueryParameters pageValues = new PubMedResultQueryParameters();
	
	public CrawlerPubMed(String url, String query) throws CrawlerException {
		this.url = url;
		this.query = query;
		
		try {
			this.page = WebClientFactory.newHtmlPage(new URL(this.url + this.query)); // this.webClient.getPage(this.url + this.query);
			
			this.verifySearch(this.page);
			this.manageResultValues(this.page);
			System.out.println("===========================================================================");
			
		} catch (FactoryException e) {
			throw new CrawlerException(e.getMessage());
		} catch (MalformedURLException e) {
			throw new CrawlerException(e.getMessage());
		}
		
	}
	
	/**
	 * The <code>pageValues</code> object manage the parameter results of a user query.
	 * @param page
	 * @throws CrawlerException
	 */
	private void manageResultValues(HtmlPage page) throws CrawlerException {
		this.pageValues.setNumOfTotalItems(ParserPubMed.findNumberOfResultItems(page));
		this.pageValues.setNumOfAvailablePage(ParserPubMed.numberOfResultPage(page));
		this.pageValues.setNumOfResultPerPage(ParserPubMed.pageSize(page));
		
 		/* trovo il numero di pagine complete di tutti i risultati */
		int pageToManage = this.pageValues.getNumOfAvailablePage() - 1;
		this.pageValues.setMaxNumOfPageToManage(pageToManage);
	}

	/**
	 * This method verify whether the query term(s) contain mistakes.
	 * If the term has mistake(s), the system correct it and launch the a new query with the correct term(s).
	 * 
	 * @param page
	 */
	private void verifySearch(HtmlPage page) {
		HtmlAnchor aSpellSugg;
		try {
			aSpellSugg = (HtmlAnchor) page.getElementById("EntrezSystem2.PEntrez.Pmc.MessageBar.CorrectedQuery");
			
			this.query = aSpellSugg.getAttribute("term"); // Se la query è sbagliata la sovrascrivo
			this.page = WebClientFactory.newHtmlPage(new URL(this.url + this.query));

			System.out.println("Did you mean: " + this.query);
		} catch (ElementNotFoundException e) {
			return;
		} catch (Exception e) {
			return;
		}
		
	}
	

	/**
	 * This method manage the switching of the result pages and give to the Parser the
	 * responsibility to extract article links.
	 * 
	 * @param numPagesToBeProcessed
	 * @throws CrawlerException
	 */
	public void startup(int numPagesToBeProcessed) throws CrawlerException {
		
		try {
			
			System.out.println("Pages to be processed: " + numPagesToBeProcessed);
			System.out.println("Number of available pages for this query: " + this.pageValues.getNumOfAvailablePage());
			System.out.println("Number of total results: " + this.pageValues.getNumOfTotalItems());
			System.out.println("===========================================================================");
			
			if(this.pageValues.getNumOfAvailablePage() == 1) { // Ci sono pochi risultati da acquisire --> esco
				System.err.println("Too few result. The query will not be processed!");
				return;
			}
			
			if(this.pageValues.getMaxNumOfPageToManage() < numPagesToBeProcessed)
				numPagesToBeProcessed = this.pageValues.getMaxNumOfPageToManage(); // per evitare smezzature nell'ultima pagina
			
			/* Manage the Article list */
			List<Article> listArticle = new ArrayList<Article>(this.pageValues.getNumOfResultPerPage() * numPagesToBeProcessed);
			
			String pageParam = "&amp;EntrezSystem2.PEntrez.Pmc.Pmc_ResultsPanel.Pager.CurrPage=";
			CrawlerPubMedWorker worker = new CrawlerPubMedWorker(); // Gli delego la resp. di creare gli n articoli per pagina
			
			/* Partially filled list of Article */
			for(int i=1; i<=numPagesToBeProcessed; i++) {
				String relatveUrlPager = this.url + this.query + pageParam + Integer.toString(i); // dove i � il numero della pagina 
				URL urlPager = new URL(relatveUrlPager);
				listArticle.addAll(worker.getArticleSnippet(urlPager, this.pageValues.getNumOfResultPerPage()));
			}
			
			/* Article list full filled */
			for (Article article : listArticle) {
				worker.completeArticle(article);
			}

			System.out.println(listArticle.size());
			
		} catch (FactoryException e) {
			throw new CrawlerException(e.getMessage());
		} catch (MalformedURLException e) {
			throw new CrawlerException(e.getMessage());
		}
		
		
	}

}
